#!/usr/bin/env node
/**
 * @file dp.js - 文档变更管理工具
 * @version 1.0.0
 * @license MIT
 * @author 开发团队
 * @description 用于自动化管理文档变更日志的工具，支持多种变更类型和模块化更新
 * @see DOCUMENTATION_GUIDELINES.md 了解文档标准
 */

import { spawnSync } from 'child_process';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs/promises';
import { Command } from 'commander';

// 获取当前脚本的目录
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 定义选项和对应的脚本
const optionScripts = [
  { short: '-c', long: '--change', script: 'dp-change.js', key: 'changes' },
  { short: '-a', long: '--add', script: 'dp-add.js', key: 'additions' },
  { short: '-d', long: '--deprecate', script: 'dp-deprecate.js', key: 'deprecations' },
  { short: '-f', long: '--fix', script: 'dp-fix.js', key: 'fixes' },
  { short: '-r', long: '--remove', script: 'dp-remove.js', key: 'removals' },
  { short: '-s', long: '--security', script: 'dp-security.js', key: 'security' },
  { short: '-m', long: '--module', script: null, key: 'module' } // 添加模块选项
];

// 调试模式
const DEBUG = process.env.DEBUG === 'true';

// 配置
const CHANGELOG_PATH = path.join(__dirname, '../CHANGELOG.md');
const PACKAGE_JSON_PATH = path.join(__dirname, '../package.json');

// 主函数
async function main() {
  const args = process.argv.slice(2);
  
  if (DEBUG) {
    console.log('调试信息: 启动脚本，参数:', args);
  }
  
  // 检查帮助选项
  if (args.includes('-h') || args.includes('--help')) {
    printHelp();
    return;
  }
  
  // 如果没有参数，显示帮助信息
  if (args.length === 0) {
    console.error('错误: 至少需要提供一个变更选项 (-c, -a, -d, -f, -r, -s)');
    printHelp();
    process.exit(1);
  }
  
  try {
    // 检查是否有直接传递的描述参数（不带选项标志）
    if (args.length > 0 && !args[0].startsWith('-')) {
      if (DEBUG) {
        console.log('调试信息: 检测到直接传递的描述参数，将其视为 -a/--add 的参数');
      }
      // 如果第一个参数不是选项标志，则将其视为 -a/--add 的参数
      const newArgs = ['-a', args[0], ...args.slice(1)];
      await processAllOptions(newArgs);
      return;
    }
    
    console.log('\n🔄 正在处理文档变更...');
    
    // 处理所有选项
    await processAllOptions(args);
  } catch (error) {
    console.error(`\n❌ 错误: ${error.message}`);
    if (DEBUG) {
      console.error('调试信息: 错误堆栈:', error.stack);
    }
    process.exit(1);
  }
}

// 处理所有选项
async function processAllOptions(args) {
  // 解析所有选项和它们的参数
  const options = parseArgs(args);
  
  if (DEBUG) {
    console.log('调试信息: 解析的选项', JSON.stringify(options, null, 2));
  }
  
  // 检查是否有变更
  if (!hasChanges(options)) {
    console.error('错误: 至少需要提供一个变更选项 (-c, -a, -d, -f, -r, -s)');
    printHelp();
    process.exit(1);
  }
  
  console.log('\n📝 正在使用自动化工具更新文档变更日志...');
  
  // 读取当前版本
  const { docVersion, projectVersion } = await readVersions();
  
  if (DEBUG) {
    console.log(`调试信息: 当前文档版本 ${docVersion}, 项目版本 ${projectVersion}`);
  }
  
  // 生成唯一代码
  const uniqueCode = generateUniqueCode();
  
  // 准备变更日志条目
  const entry = generateChangelogEntry(options, projectVersion, uniqueCode);
  
  if (DEBUG) {
    console.log('调试信息: 生成的变更日志条目');
    console.log(entry);
  }
  
  // 更新变更日志
  await updateChangelog(entry);
  
  // 增加文档版本
  const newDocVersion = incrementPatchVersion(docVersion);
  await updateDocVersion(newDocVersion);
  
  console.log(`\n✅ 变更日志已更新至版本 ${newDocVersion}`);
  console.log(`   项目版本: ${projectVersion}`);
  console.log(`   变更代码: ${uniqueCode}`);
  
  if (options.module) {
    console.log(`   更新模块: ${options.module}`);
  }
  
  console.log('\n⚠️  提醒: 所有文档变更必须使用此自动化工具录入日志，禁止手动修改变更日志');
}

// 使用commander.js解析命令行参数
function parseArgs(args) {
  const program = new Command();
  
  // 配置命令基本信息
  program
    .name('dp')
    .description('文档变更管理工具')
    .version('1.0.0')
    .helpOption('-h, --help', '显示帮助信息');
  
  // 定义所有选项
  program
    .option('-c, --change <description>', '添加更改项', collectMultiple)
    .option('-a, --add <description>', '添加新增项', collectMultiple)
    .option('-d, --deprecate <description>', '添加已废弃项', collectMultiple)
    .option('-f, --fix <description>', '添加修复项', collectMultiple)
    .option('-r, --remove <description>', '添加移除项', collectMultiple)
    .option('-s, --security <description>', '添加安全项', collectMultiple)
    .option('-m, --module <name>', '指定要更新的组件/模块');
  
  // 解析参数
  program.parse(args, { from: 'user' });
  const options = program.opts();
  
  // 转换选项格式以保持向后兼容
  return {
    help: false, // commander.js已处理帮助选项
    changes: options.change || [],
    additions: options.add || [],
    deprecations: options.deprecate || [],
    fixes: options.fix || [],
    removals: options.remove || [],
    security: options.security || [],
    module: options.module || null
  };
}

// 收集多个相同选项的值
function collectMultiple(value, previous) {
  return previous ? [...previous, value] : [value];
}

// 检查是否有变更
function hasChanges(options) {
  return (
    options.changes.length > 0 ||
    options.additions.length > 0 ||
    options.deprecations.length > 0 ||
    options.fixes.length > 0 ||
    options.removals.length > 0 ||
    options.security.length > 0
  );
}

// 读取版本信息
async function readVersions() {
  // 读取文档版本
  const changelogContent = await fs.readFile(CHANGELOG_PATH, 'utf8');
  const docVersionMatch = changelogContent.match(/Document Version: (\d+\.\d+\.\d+)/);
  
  if (!docVersionMatch) {
    throw new Error('无法从变更日志中读取文档版本');
  }
  
  const docVersion = docVersionMatch[1];
  
  // 读取项目版本
  const packageJsonContent = await fs.readFile(PACKAGE_JSON_PATH, 'utf8');
  const packageJson = JSON.parse(packageJsonContent);
  const projectVersion = packageJson.version;
  
  return { docVersion, projectVersion };
}

// 生成唯一代码
function generateUniqueCode() {
  const now = new Date();
  const datePart = now.getFullYear().toString().slice(2) + 
                  padZero(now.getMonth() + 1) + 
                  padZero(now.getDate());
  
  const randomPart = Math.random().toString(36).substr(2, 3).toUpperCase();
  
  return `${datePart}${randomPart}`;
}

// 生成变更日志条目
function generateChangelogEntry(options, projectVersion, uniqueCode) {
  const now = new Date();
  const date = `${now.getFullYear()}-${padZero(now.getMonth() + 1)}-${padZero(now.getDate())}`;
  
  // 使用传入的项目版本号
  let entry = `## [${projectVersion}] - ${date} (${uniqueCode})`;
  
  // 如果指定了模块，添加模块信息
  if (options.module) {
    entry += ` [${options.module}]`;
  }
  
  entry += `\n\n`;
  
  if (options.changes.length > 0) {
    entry += "### 更改\n";
    options.changes.forEach(change => {
      entry += `- ${change}\n`;
    });
    entry += "\n";
  }
  
  if (options.additions.length > 0) {
    entry += "### 新增\n";
    options.additions.forEach(add => {
      entry += `- ${add}\n`;
    });
    entry += "\n";
  }
  
  if (options.deprecations.length > 0) {
    entry += "### ~~已废弃~~\n";
    options.deprecations.forEach(deprecate => {
      entry += `- ${deprecate}\n`;
    });
    entry += "\n";
  }
  
  if (options.fixes.length > 0) {
    entry += "### 修复\n";
    options.fixes.forEach(fix => {
      entry += `- ${fix}\n`;
    });
    entry += "\n";
  }
  
  if (options.removals.length > 0) {
    entry += "### 移除\n";
    options.removals.forEach(remove => {
      entry += `- ${remove}\n`;
    });
    entry += "\n";
  }
  
  if (options.security.length > 0) {
    entry += "### 安全\n";
    options.security.forEach(security => {
      entry += `- ${security}\n`;
    });
    entry += "\n";
  }
  
  return entry;
}

// 更新变更日志
async function updateChangelog(entry) {
  const changelogContent = await fs.readFile(CHANGELOG_PATH, 'utf8');
  
  // 在第一个 ## 之前插入新条目
  const firstEntryIndex = changelogContent.indexOf('## [');
  
  if (firstEntryIndex === -1) {
    throw new Error('无法在变更日志中找到条目位置');
  }
  
  const newChangelogContent = 
    changelogContent.slice(0, firstEntryIndex) + 
    entry + 
    changelogContent.slice(firstEntryIndex);
  
  await fs.writeFile(CHANGELOG_PATH, newChangelogContent, 'utf8');
}

// 增加修正版本号
function incrementPatchVersion(version) {
  const parts = version.split('.');
  parts[2] = (parseInt(parts[2], 10) + 1).toString();
  return parts.join('.');
}

// 更新文档版本
async function updateDocVersion(newVersion) {
  const changelogContent = await fs.readFile(CHANGELOG_PATH, 'utf8');
  
  // 更新文档版本
  const updatedContent = changelogContent.replace(
    /Document Version: \d+\.\d+\.\d+/,
    `Document Version: ${newVersion}`
  );
  
  await fs.writeFile(CHANGELOG_PATH, updatedContent, 'utf8');
}

// 补零
function padZero(num) {
  return num.toString().padStart(2, '0');
}

// 打印帮助信息
function printHelp() {
  console.log(`
使用方法: npm run dp [选项] [描述]

选项:
  -c, --change "描述"      添加更改项
  -a, --add "描述"         添加新增项
  -d, --deprecate "描述"   添加已废弃项
  -f, --fix "描述"         添加修复项
  -r, --remove "描述"      添加移除项
  -s, --security "描述"    添加安全项
  -m, --module "模块名"    指定要更新的组件/模块
  -h, --help               显示此帮助信息

示例:
  npm run dp -a "新添加dp脚本" -d "废弃其他日程管理脚本" -f "给脚本打了补丁"
  npm run dp -m "Button" -a "添加新的按钮样式" -f "修复按钮点击事件"

此命令会自动:
  1. 生成唯一的六位变更码
  2. 更新变更日志，添加新条目
  3. 自增文档版本的修正号
  4. 同步项目版本到变更日志

重要说明:
  * 所有文档变更必须使用此自动化工具录入日志，禁止手动修改变更日志
  * 使用 -m/--module 选项可以指定单个组件进行更新，推荐每次只更新一个组件
`);
}

// 执行主函数
main().catch(error => {
  console.error(`错误: ${error.message}`);
  process.exit(1);
});